package com.wiscamp.ninechapters.panels.domain.services;

import com.wiscamp.ninechapters.panels.domain.repositories.PanelsErrorCodes;
import com.wiscamp.ninechapters.panels.domain.entities.Menu;
import com.wiscamp.ninechapters.panels.domain.entities.Permission;
import com.wiscamp.ninechapters.panels.domain.entities.Role;
import com.wiscamp.ninechapters.panels.domain.repositories.MenuRepository;
import com.wiscamp.ninechapters.panels.domain.repositories.PermissionRepository;
import com.wiscamp.ninechapters.panels.domain.repositories.RoleRepository;
import cube.common.cache.CacheManagerNames;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.domain.DomainService;
import cube.ddd.exception.ExceptionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

@Service
public class RoleService implements DomainService {
    private final RoleRepository roleRepository;

    private final MenuRepository menuRepository;

    private final PermissionRepository permissionRepository;

    private final String cacheName = "roles";

    public RoleService(RoleRepository roleRepository, MenuRepository menuRepository, PermissionRepository permissionRepository) {
        this.roleRepository = roleRepository;
        this.menuRepository = menuRepository;
        this.permissionRepository = permissionRepository;
    }

    @HandleServiceException
    @Cacheable(value = cacheName, key = "#roleId", cacheManager = CacheManagerNames.SIXTY_MINUTES_CACHE)
    public Role getRole(long roleId) {
        var role = roleRepository.getRole(roleId);
        if (Objects.isNull(role)) {
            ExceptionUtils.throwServiceException(PanelsErrorCodes.PARAMETER_NOT_FOUND, roleId);
        }
        return role;
    }


    @HandleServiceException
    public Collection<Menu> getMenusByRole(long roleId) {
        var role = getRole(roleId);
        if (Objects.nonNull(role) && !role.getMenuIds().isEmpty()) {
            return menuRepository.getMenusByIds(role.getMenuIds());
        }
        return new ArrayList<>();
    }

    @HandleServiceException
    public Collection<Permission> getPermissionsByRole(long roleId) {
        var role = getRole(roleId);
        if (Objects.nonNull(role) && !role.getPermissionIds().isEmpty()) {
            return permissionRepository.getPermissionsByIds(role.getPermissionIds());
        }
        return new ArrayList<>();
    }

    @HandleServiceException
    @CachePut(value = cacheName, key = "#role.roleId", cacheManager = CacheManagerNames.SIXTY_MINUTES_CACHE)
    public Role createRole(Role role, long operatorId) {
        var existedRole = roleRepository.getRoleByCode(role.getApplicationId(), role.getRoleCode());
        if (Objects.nonNull(existedRole)) {
            ExceptionUtils.throwServiceException(PanelsErrorCodes.PARAMETER_CODE_EXISTED, role);
        }

        role.createBy(operatorId);
        return roleRepository.saveRole(role);
    }

    @HandleServiceException
    @CachePut(value = cacheName, key = "#role.roleId", cacheManager = CacheManagerNames.SIXTY_MINUTES_CACHE)
    public Role updateRole(Role role, long operatorId) {
        var existedRole = getRole(role.getRoleId());
        existedRole = roleRepository.getRoleByCode(role.getApplicationId(), role.getRoleCode());
        if (Objects.nonNull(existedRole) && existedRole.getRoleId() != role.getRoleId()) {
            ExceptionUtils.throwServiceException(PanelsErrorCodes.PARAMETER_CODE_EXISTED, role);
        }
        role.updateBy(operatorId);
        return roleRepository.saveRole(role);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean enableRole(long roleId, long operatorId) {
        var role = getRole(roleId);
        if (Objects.isNull(role)) return false;
        // 记录操作日志
        role.enable();
        role.updateBy(operatorId);
        roleRepository.saveRole(role);
        return true;
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean disableRole(long roleId, long operatorId) {
        var role = getRole(roleId);
        if (Objects.isNull(role)) return false;
        // 记录操作日志
        role.disable();
        role.updateBy(operatorId);
        roleRepository.saveRole(role);
        return true;
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean deleteRole(long roleId, long operatorId) {
        var role = getRole(roleId);
        if (Objects.isNull(role)) return false;
        // 记录操作日志
        role.delete();
        role.updateBy(operatorId);
        roleRepository.saveRole(role);
        return true;
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean bindRoleMenu(long roleId, long menuId) {
        return roleRepository.bindRoleMenu(roleId, menuId);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean unbindRoleMenu(long roleId, long menuId) {
        return roleRepository.unbindRoleMenu(roleId, menuId);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean bindRolePermission(long roleId, long permissionId) {
        return roleRepository.bindRolePermission(roleId, permissionId);
    }

    @HandleServiceException
    @CacheEvict(value = cacheName, key = "#roleId")
    public boolean unbindRolePermission(long roleId, long permissionId) {
        return roleRepository.unbindRolePermission(roleId, permissionId);
    }
}
